// File:			R1.cpp
// Authors:			Richard Burris, Joshua Douty
// Purpose:			R1 work file
// Version:        	3.0
// Date:			11/03/2011

#include "mpx_supt.h"
#include "R1.h"
#include "R2.h"
#include "R3.h"
#include "R4.h"

//First buffer where the unaltered first goes
char buf[80];
//Where only the name of the command is stored
char shortCom[80];
//Where the cleaned up command is stored
char runCom[80];
//Where the parameter for a command is stored
char par[80];
date_rec *Date;
int size;

//Check if we need to get a new date or if one has already been called
int getNewDate = TRUE;

//Console print out
char* str1 = "Richard Burris and Joshua Douty's MPX\n\n\0";
char* str2 = "This console is case sensitive!\n\n\0";

void clean();
void cleanCom();
void comhand();
void console();
void date(char);
void directory(char);
void exit(char);
void intro();
void readHelp(char[]);
void version(char);


void main() {
	sys_init(MODULE_R4);
	intro();
	sys_set_vec(sys_call);
	console();
	
}

/*
	Procedure: clean

	Purpose: Clean up memory before the program terminates

	Parameters: None        

	Return value: None

	Calls: sys_free_mem  

	Globals: none

	Errors: none
*/
void clean() {
	sys_free_mem (buf);
	sys_free_mem (runCom);
	sys_free_mem (shortCom);
	sys_free_mem (par);
}

/*
	Procedure: cleanCom

	Purpose: Cleans up the command entered by the user

	Parameters: None        

	Return value: None

	Calls: None

	Globals: none

	Errors: none
*/
void cleanCom() {
	int i;
	//Place a null terminating char at the beginning
	shortCom[0] = '\0';
	for(i = 0; i < 80; i++) {
		
		//Getting the name out of runCom
		if(runCom[i] == ' ') {
			size = strlen(shortCom);
			shortCom[size] = '\n';
			return;

		} else {
			strncpy(shortCom, runCom, (i+1));
		}
	}
}

/*
	Procedure: console

	Purpose: Display the console and accept input

	Parameters: None        

	Return value: None

	Calls: 	sys_free_mem  
			sys_req

	Globals: 	buf
				runCom

	Errors: none
*/
void console() {
	for(;;) {
		//Making sure all the buffers are empty 
		for(int i = 0; i<80; i++) {
			buf[i] = '\0';
			shortCom[i] = '\0';
			runCom[i] = '\0';
			par[i] = '\0';
		}
		
		//Prints out the Console and waits for input
		char* str0 = "\n\n>> \0";
		size = strlen(str0);
		strcpy (buf, str0);
		sys_req(WRITE, TERMINAL, buf, &size);
		size = 80;
		sys_req(READ, TERMINAL, buf, &size);

		//Exploit strlen to just read the input string 
		size = strlen(buf);
		strncpy (runCom, buf, size);
		runCom[size] = '\0';
		
		cleanCom();
		
		//Sends the command to the Command handler function
		comhand();
		
		//Free the memory from the char array
		sys_free_mem (str0);
	}
}

/*
	Procedure: comhand

	Purpose: Call the correct methods for the input

	Parameters: None        

	Return value: None

	Calls: 	exit
			version
			date
			directory
			readHelp
			sys_req

	Globals: 	runCom

	Errors: none
*/
void comhand() {
	int ComSize = strlen(shortCom)-1;
	char arg = '*';
	
	//Determining the parameter character 
	//i.e. getting the '?' from /?
	int argSize = strlen(runCom);
	for(int n=0;n<argSize;n++) {
		if(runCom[n] == '/') {
			arg = runCom[n+1];
		}
	}

	//Fishing out the parameter list from the command
	int t = 0;
	for(int k=ComSize+1;k<argSize;k++) {
		par[t] = runCom[k];
		t = t+1;
	}
	par[t-1]='\0';
	
	if (strncmp(shortCom, "exit", ComSize) == 0 && (ComSize == 4)) {
		exit(arg);
	} else if (strncmp(shortCom, "version", ComSize) == 0 && (ComSize == 7)) {
		version(arg);
	} else if (strncmp(shortCom, "date", ComSize) == 0 && (ComSize == 4)) {
		date(arg);
	} else if (strncmp(shortCom, "directory", ComSize) == 0 && (ComSize == 9)) {
		directory(arg);
	} else if (strncmp(shortCom, "/?", ComSize) == 0 && (ComSize == 2)) {
		readHelp("help.txt");
	} else if (strncmp(shortCom, "create", ComSize) == 0 && (ComSize == 6)) {
		createPCB(par, arg); 
	} else if (strncmp(shortCom, "delete", ComSize) == 0 && (ComSize == 6)) {
		deletePCB(par, arg); 
	} else if (strncmp(shortCom, "block", ComSize) == 0 && (ComSize == 5)) {
		blockPCB(par, arg); 
	} else if (strncmp(shortCom, "unblock", ComSize) == 0 && (ComSize == 7)) {
		unblockPCB(par, arg); 
	} else if (strncmp(shortCom, "suspend", ComSize) == 0 && (ComSize == 7)) {
		suspendPCB(par, arg); 
	} else if (strncmp(shortCom, "resume", ComSize) == 0 && (ComSize == 6)) {
		resumePCB(par, arg); 
	} else if (strncmp(shortCom, "setpriority", ComSize) == 0 && (ComSize == 11)) {
		setPriorityPCB(par, arg); 
	} else if (strncmp(shortCom, "show", ComSize) == 0 && (ComSize == 4)) {
		showPCB(par, arg);
	} else if (strncmp(shortCom, "showall", ComSize) == 0 && (ComSize == 7)) {
		showAllPCB(par, arg); 
	} else if (strncmp(shortCom, "showready", ComSize) == 0 && (ComSize == 9)) {
		showReadyPCB(par, arg); 
	} else if (strncmp(shortCom, "showblocked", ComSize) == 0 && (ComSize == 11)) {
		showBlockedPCB(par, arg); 
	} else if (strncmp(shortCom, "load_test", ComSize) == 0 && (ComSize == 9)) {
		loadProcess(arg); 
	} else if (strncmp(shortCom, "dispatch", ComSize) == 0 && (ComSize == 8)) {
		calldispatch(arg);
	} else if (strncmp(shortCom, "load", ComSize) == 0 &&(ComSize == 4)){
		load(par, arg);
	}else if(strncmp(shortCom, "terminate", ComSize) == 0 &&(ComSize == 9)){
		kill(par, arg);
	} else {
		int temp = 50;
		sys_req(WRITE, TERMINAL, "Unknown Command, Please enter the command again...", &temp);	
	}
}

/*
	Procedure: date

	Purpose:	Display date
				Set date

	Parameters: None        

	Return value: None

	Calls: 	readHelp
			sys_req

	Globals: date

	Errors: None	
*/
void date(char arg) {

	if (arg == '?') {
		readHelp("date.txt");
	} else if (arg == 's') {
			int loc = -9;
			
			//Looking for the first '-' so we know where the date is in the buffer
			for(int n=0;n<80;n++) {
				if(runCom[n] == '-') {
					loc = n;
					n=80;
				}
			}	
	
	
		//Holds the Month
		char m[3];
		//Holds the Day
		char d[3];
		//Holds the year
		char y[5];
		
		//Copies the M, D, and Y from their location in runCom
		strncpy(m, &runCom[loc-2], 2);
		strncpy(d, &runCom[loc+1], 2);
		strncpy(y, &runCom[loc+4], 4);
		
		//Null terminate the end
		m[2] = '\0';
		d[2] = '\0';
		y[4] = '\0';
		
		//Turnes the Char array to Integers 
		int mon = atoi(m);
		int da = atoi(d);
		int yr = atoi(y);
		
			//Checks the range of the month
			if ((mon>12)|| (mon<1)){
				int temp = 34;
				sys_req(WRITE, TERMINAL, "Please Enter a month between 1-12.", &temp);
				return;
			} else {	
				if((yr%4)==0){ //leap year
					//Because Wikipedia Told us to
					if((yr%100)==0) {
						if((yr%400)==0) {
							if(mon==02){ //if february
								if((da>29)||(da<1)){
									int temp = 51;
									sys_req(WRITE, TERMINAL, "That year is a leap year, day must be between 1-29.", &temp);
									return;
								}
							}
						}
					} else {
						//Checks the range of the day
						if((da>29)||(da<1)){
							int temp = 51;
							sys_req(WRITE, TERMINAL, "That year is a leap year, day must be between 1-29.", &temp);
							return;
						}
					}
				} else {
					//Checking if the appropriate month has 31 days
					if((mon==1)||(mon==3)||(mon==5)||(mon==7)||(mon==8)|| (mon==10)||(mon==12)){
						if((da>31)||(da<1)){
							int temp = 25;
							sys_req(WRITE, TERMINAL, "Day must be between 1-31.", &temp);	
							return;
						}
					} else if(mon == 02){//february
						if((da>28)||(da<1)){
							int temp = 25;
							sys_req(WRITE, TERMINAL, "Day must be between 1-28.", &temp);
							return;
						}	
					} else {
						//Otherwise check if the days are correct
						if((da>30)||(da<1)){
							int temp = 25;
							sys_req(WRITE, TERMINAL, "Day must be between 1-30.", &temp);
							return;
						}
					}
				}
			}
		//Checking to make sure the years are positive 
		if(yr < 1000) {
			int temp = 28;
			sys_req(WRITE, TERMINAL, "Please enter different year.", &temp);
			return;
		}
		
		//Setting Month, Day, and Year
		Date->month = mon;
		Date->day   = da;
		Date->year  = yr;
		
		//No longer need to get a new date
		getNewDate = FALSE;
		
	//If no parameter for setting date and only retreiving date 	
	} else if (arg == '*') {
		//If we need to get a new date because one hasn't been set by the user
		if (getNewDate == TRUE) {
			sys_get_date(Date);
			getNewDate = FALSE;	
		}
		
		//No longer need to get a new date
		getNewDate = FALSE;
		
		int temp;
	
		//Print Month
		int DATE = Date->month;
		char charDate[2];
		//itoa = Int to Array
		itoa(DATE, charDate, 10);
		//Printing month making sure not to have extra space
		if (DATE <= 9) {
			temp = 1;
			sys_req(WRITE, TERMINAL, charDate, &temp);
			temp = 1;
			sys_req(WRITE, TERMINAL, "-", &temp);
		} else {
			temp = 2;
			sys_req(WRITE, TERMINAL, charDate, &temp);
			temp = 1;
			sys_req(WRITE, TERMINAL, "-", &temp);
		}
	
		//Print Day
		int DAY = Date->day;
		char charDay[2];
		//itoa = Int to Array
		itoa(DAY, charDay, 10);
		//Printing Day making sure not to have extra space
		if (DAY <= 9) {
			temp = 1;
			sys_req(WRITE, TERMINAL, charDay, &temp);
			temp = 1;
			sys_req(WRITE, TERMINAL, "-", &temp);
		} else {
			temp = 2;
			sys_req(WRITE, TERMINAL, charDay, &temp);
			temp = 1;
			sys_req(WRITE, TERMINAL, "-", &temp);
		}
	
		//Print Year
		int YEAR = Date->year;
		char charYear[4];
		//itoa = Int to Array
		itoa(YEAR, charYear, 10);
		//Printing year
		temp = 4;
		sys_req(WRITE, TERMINAL, charYear, &temp);
	} else {
		//Arguments are unknown
		int temp = 17;
		sys_req(WRITE, TERMINAL, "Unknown Argument!", &temp);
	}
}

/*
	Procedure: directory

	Purpose: Lists the directory of .mpx files

	Parameters: None        

	Return value: None

	Calls: 	readHelp
			sys_open_dir
			sys_req
			sys_get_entry
			sys_close_dir
			sys_free_mem

	Globals: none

	Errors: none
*/
void directory(char arg) {
	if (arg == '?') {
		readHelp("dir.txt");
	} else if (arg == '*') {
		int size = 1;
		sys_req(WRITE, TERMINAL, " ", &size);	
	
		//Setting up the variables 
		char name[20];
		char fsize[100];
		int nameSize = 20;
		long *fileSize;
	
		//Setting the active directory
		sys_open_dir("C:\\TurboC\\MPX\\mpx");
	
		//Print Title
		char title[] = "Name            Size\n";
		char dash[]  = "-----           -----\n";
		int t = strlen(title);
		sys_req(WRITE, TERMINAL, title, &t);
		t = strlen(dash);
		sys_req(WRITE, TERMINAL, dash, &t);
	
		int page = 0;
		for(;;) {
			//Pagination check
			if(page<15) {
				//Adding up the number of lines
				page = page + 1;
				//Checks if there are any left to print
				if (sys_get_entry(name, nameSize, fileSize) == 0) {
					//Print Name
					int temp = strlen(name);
					if (temp <= 15) {
						sys_req(WRITE, TERMINAL, name, &temp);
					} else {
						temp = 15;
						sys_req(WRITE, TERMINAL, name, &temp);
					}
			
					//Print Spaces
					int i = temp;
					for(i; i <= 15; i++) {
						temp = 1;
						sys_req(WRITE, TERMINAL, " ", &temp);
					}
			
			
					//Print Size
					ltoa(*fileSize, fsize, 10);
					temp = strlen(fsize);
					sys_req(WRITE, TERMINAL, fsize, &temp);
			
					//Print \n
					temp = 1;
					sys_req(WRITE, TERMINAL, "\n", &temp);
				//All the files have printed
				} else {
					sys_close_dir();
					sys_free_mem(name);
					return;
				}
			} else {
				//Prints for pagination
				page = 0;
				char* PageNat = "\nPress any key to continue\n\0";
				size = strlen(PageNat);
				sys_req(WRITE, TERMINAL, PageNat, &size);
				//size = 1;
				sys_req(READ, TERMINAL, buf, &size);
				sys_free_mem(PageNat);
			}
		}
	} else {
		int temp = 19;
		sys_req(WRITE, TERMINAL, "Unknown Argument \n", &temp);
	}
}

/*
	Procedure: exit

	Purpose: Cleans up memory and then exits the program

	Parameters: None        

	Return value: None

	Calls: 	readHelp
			sys_req
			clean
			sys_exit
			intro

	Globals: none

	Errors: none
*/
void exit(char arg) {
	if (arg == '?') {	
		readHelp("exit.txt");
	} else if (arg == '*') {
		//Exit prompt
		int temp = 52;
		sys_req(WRITE, TERMINAL, "Please type yes to exit!\nOr press enter to continue", &temp);
	
		//Prints out the Console and waits for input
		char* str0 = "\n\n> \0";
		size = strlen(str0);
		strcpy (buf, str0);
		sys_req(WRITE, TERMINAL, buf, &size);
		size = 80;
		sys_req(READ, TERMINAL, buf, &size);
	
		//If prompt is yes then cleanup and exit
		if (strncmp(buf, "yes", 3) == 0) {
			int temp = 14;
			sys_req(WRITE, TERMINAL, "Exiting Now...", &temp);
			clean();
			deleteAllPCB();
			sys_exit();
		}
		//If not cleanup arrays and reprint intro
		clean();	
		intro();
	} else {
		int temp = 16;
		sys_req(WRITE, TERMINAL, "Unknown Argument", &temp);
	}
}

/*
	Procedure: intro

	Purpose: Displays the introduction messages

	Parameters: None        

	Return value: None

	Calls: sys_req 

	Globals: buf

	Errors: none
*/
void intro() {
	//Gets the size of intro string
	//Then prints it all out
	size = strlen(str1);
	strcpy (buf, str1);
	sys_req(WRITE, TERMINAL, buf, &size);
	
	//Gets the size of intro string
	//Then prints it all out
	size = strlen(str2);
	strcpy (buf, str2);
	sys_req(WRITE, TERMINAL, buf, &size);
}

/*
	Procedure: readHelp

	Purpose: Clean up memory before the program terminates

	Parameters: None        

	Return value: None

	Calls: sys_free_mem  

	Globals: none

	Errors: none
*/
void readHelp(char fname[]) {

	//Addings the full path to the beginning
	char filename[50] = "C:\\TurboC\\MPX\\help\\";
	strcat(filename, fname);
	
	//Opens a file with the flag for reading
	FILE *file = fopen (filename, "r" );
	int i, j;

	//Char array for a single line
	char line[128]; /* or other suitable maximum line size */ 

	for(i=0; i<128; i++)
	line[i] = '\0';

	if ( file != NULL ) { 

		i=0; 

		while ( fgets ( line, sizeof line, file ) != NULL ) /* read a line */ {
			//Writing the line
			int temp = strlen(line);
			sys_req(WRITE, TERMINAL, line, &temp);
		
			i++;
		}
	
		fclose ( file );
	}
	else {
		perror ( filename ); /* why didn't the file open? */
	}
}

/*
	Procedure: version

	Purpose: Displays the version information

	Parameters: None        

	Return value: None

	Calls: 	readHelp 
			sys_req
			sys_free_mem

	Globals: none

	Errors: none
*/
void version(char arg) {
	if (strncmp(runCom, "version /?", 10) == 0) {
		readHelp("version.txt");
	} else {
		//Setting up the string for version
		char* version = "MPX Version: 6.0 - R6, Final Alpha Release\n";		
		int temp = strlen(version);
		sys_req(WRITE, TERMINAL, version, &temp);
		
		//Setting up the string for the date
		char* date = "Build Date: 12-8-11";
		temp = strlen(date);
		sys_req(WRITE, TERMINAL, date, &temp);
	
		//Frees up the two arrays that were allocated
		sys_free_mem (version);
		sys_free_mem (date);
	}
}